/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.spayc;

/**
 *
 * @author Kehinde
 */
class Region3 {
    // Shared coefficients for Region 3
    protected static int i[] = {00,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,2,3,3,
    3,3,3,4,4,4,4,5,5,5,6,6,6,7,8,9,9,10,10,11};
    protected static int j[] = {00,0,1,2,7,10,12,23,2,6,15,17,0,2,6,7,22,26,0,2,
    4,16,26,0,2,4,26,1,3,26,0,2,26,2,26,2,26,0,1,26};
    protected static double n[] = {1.0658070028513,-15.732845290239,
    20.944396974307,-7.6867707878716,2.6185947787954,-2.8080781148620,
    1.2053369696517,-8.4566812812502E-3,-1.2654315477714,-1.1524407806681,
    0.88521043984318,-0.64207765181607,0.38493460186671,-0.85214708824206,
    4.8972281541877,-3.0502617256965,3.9420536879154E-2,0.12558408424308,
    -0.27999329698710,1.3899799569460,-2.0189915023570,-8.2147637173963E-3,
    -0.47596035734923,4.3984074473500E-2,-0.44476435428739,0.90572070719733,
    0.70522450087967,0.10770512626332,-0.32913623258954,-0.50871062041158,
    -2.2175400873096E-2,9.4260751665092E-2,0.16436278447961,-1.3503372241348E-2,
    -1.4834345352472E-2,5.7922953628084E-4,3.2308904703711E-3,8.0964802996215E-5,
    -1.6557679795037E-4,-4.4923899061815E-5};

    /** Helmholtz Free Energy f(ρ, T)
     *
     * @param rho density
     * @param t absolute temperature
     * @return
     */
    public static double f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return phi(delta, tau) * SteamCalc.R * t;
    }

    /** Pressure
     *
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double p(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return delta * phi_delta(delta, tau) * rho * SteamCalc.R * t/1000; // 1000 correction factor
    }

    /** Specific internal energy u
     * 
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double u_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return tau * phi_tau(delta, tau) * SteamCalc.R * t;
    }

    /**
     * Specific internal energy
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double u(double p, double t) {
        return u_f(1/v(p, t), t);
    }

    /** Specific entropy s
     *
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double s_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return (tau * phi_tau(delta, tau) - phi(delta, tau)) * SteamCalc.R;
    }

    /**
     * Specific entropy
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double s(double p, double t) {
        return s_f(1/v(p, t), t);
    }

    /**
     * Specific enthalpy
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double h_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return (tau * phi_tau(delta, tau) + delta * phi_delta(delta, tau)) * SteamCalc.R * t;
    }

    /**
     * Specific enthalpy
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double h(double p, double t) {
        return h_f(1/v(p, t), t);
    }

    /** Specific isochoric heat capacity Cv
     *
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double cv_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;

        return -tau*tau * phi_tau2(delta, tau) * SteamCalc.R;
    }

    /**
     * Specific isochoric heat capacity Cv
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double cv(double p, double t) {
        return cv_f(1/v(p, t), t);
    }
    
    /**
     * Specific isobaric heat capacity Cp
     * @param rho density
     * @param t temperature
     * @return
     */
    public static double cp_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;
        double a = delta * phi_delta(delta, tau);
        double b = delta * tau * phi_delta_tau(delta, tau);
        double c = delta * delta * phi_delta2(delta, tau);

        return cv_f(rho, t) + SteamCalc.R * (a-b)*(a-b)/(2*a + c);
    }

    /**
     * Specific isobaric heat capacity Cp
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double cp(double p, double t) {
        return cp_f(1/v(p, t), t);
    }

    /**
     * Speed of sound
     * @param rho density
     * @param t absolute temperature
     * @return
     */
    public static double w_f(double rho, double t) {
        double delta = rho/SteamCalc.RHOc;
        double tau = SteamCalc.Tc/t;
        double a = delta * phi_delta(delta, tau);
        double b = delta * tau * phi_delta_tau(delta, tau);
        double c = delta*delta * phi_delta2(delta, tau);
        double d = tau*tau * phi_tau2(delta, tau);

        return Math.sqrt((2*a + c - (a-b)*(a-b)/d) * SteamCalc.R * t*1000); // 1000 is correction factor - dunno why.
    }

    /**
     * Speed of sound
     * @param p pressure
     * @param t temperature
     * @return
     */
    public static double w(double p, double t) {
        return w_f(1/v(p, t), t);
    }

    static double phi(double delta, double tau) {
        double phi = n[0] * Math.log(delta);

        for (int k=1; k<40; k++) {
            phi += n[k] * Math.pow(delta, i[k]) * Math.pow(tau, j[k]);
        }

        return phi;
    }

    static double phi_delta(double delta, double tau) {
        double phi_delta = n[0]/delta;

        for (int k=1; k<40; k++) {
            phi_delta += n[k] * i[k] * Math.pow(delta, i[k]-1) * Math.pow(tau, j[k]);
        }

        return phi_delta;
    }

    static double phi_delta2(double delta, double tau) {
        double phi_delta = -n[0]/(delta*delta);

        for (int k=1; k<40; k++) {
            phi_delta += n[k] * i[k] * (i[k]-1) * Math.pow(delta, i[k]-2) * Math.pow(tau, j[k]);
        }

        return phi_delta;
    }

    static double phi_tau(double delta, double tau) {
        double phi_tau = 0;

        for (int k=1; k<40; k++) {
            phi_tau += n[k] * j[k] * Math.pow(delta, i[k]) * Math.pow(tau, j[k]-1);
        }

        return phi_tau;
    }

    static double phi_tau2(double delta, double tau) {
        double phi_tau = 0;

        for (int k=1; k<40; k++) {
            phi_tau += n[k] * j[k] * (j[k]-1) * Math.pow(delta, i[k]) * Math.pow(tau, j[k]-2);
        }

        return phi_tau;
    }

    static double phi_delta_tau(double delta, double tau) {
        double phi_delta_tau = 0;

        for (int k=1; k<40; k++) {
            phi_delta_tau += n[k] * i[k] * j[k] * Math.pow(delta, i[k]-1) * Math.pow(tau, j[k]-1);
        }

        return phi_delta_tau;
    }

    // Backward equations
    static double h3ab(double p) {
        double p__ = 1; // MPa
        double h__ = 1; // kJ/kg
        double pi = p/p__;
        double n1 = 2014.64004206875;
        double n2 = 3.74696550136983;
        double n3 = -2.19921901054187E-2;
        double n4 = 8.75131686009950E-5;
        double eta = n1 + (n2 + (n3 + n4 * pi) * pi) * pi;
        return eta * h__;
    }
    public static double v_ph(double p, double h) {
        if (h > h3ab(p)) return v_ph3b(p, h);
        else return v_ph3a(p, h);
    }

    static double v_ph3a(double p, double h) {
        int i_[] = {-12,-12,-12,-12,-10,-10,-10,-8,-8,-6,-6,-6,-4,-4,-3,-2,-2,-1,
        -1,-1,-1,0,0,1,1,1,2,2,3,4,5,8};
        int j_[] = {6,8,12,18,4,7,10,5,12,3,4,22,2,3,7,3,16,0,1,2,3,0,1,0,1,2,0,
        2,0,2,2,2};
        double n_[] = {5.29944062966028E-3,-0.170099690234461,11.1323814312927,
        -2178.98123145125,-5.06061827980875E-4,0.556495239685324,-9.43672726094016,
        -0.297856807561527,93.9353943717186,1.92944939465981E-2,0.421740664704763,
        -3.68914126282330E6,-7.37566847600639E-3,-0.354753242424366,-1.99768169338727,
        1.15456297059049,5683.66875815960,8.08169540124668E-3,0.172416341519307,
        1.04270175292927,-0.297691372792847,0.560394465163593,0.275234661176914,
        -0.148347894866012,-6.51142513478515E-2,-2.92468715386302,6.64876096952665E-2,
        3.52335014263844,-1.46340792313332E-2,-2.24503486668184,1.10533464706142,
        -4.08757344495612E-2};
        double v__ = 0.0028; // m3/kg
        double p__ = 100; // MPa
        double h__ = 2100; // kJ/kg
        double pi = p/p__;
        double eta = h/h__;
        double omega = 0;

        for (int k=0; k<32; k++) {
            omega += n_[k] * Math.pow(pi+0.128, i_[k]) * Math.pow(eta-0.727, j_[k]);
        }

        return omega * v__;
    }

    static double v_ph3b(double p, double h) {
        int i_[] = {-12,-12,-8,-8,-8,-8,-8,-8,-6,-6,-6,-6,-6,-6,-4,-4,-4,-3,-3,
        -2,-2,-1,-1,-1,-1,0,1,1,2,2};
        int j_[] = {0,1,0,1,3,6,7,8,0,1,2,5,6,10,3,6,10,0,2,1,2,0,1,4,5,0,0,1,2,6};
        double n_[] = {-2.25196934336318E-9,1.40674363313486E-8,2.33784085280560E-6,
        -3.31833715229001E-5,1.07956778514318E-3,-0.271382067378863,1.07202262490333,
        -0.853821329075382,-2.15214194340526E-5,7.69656088222730E-4,-4.31136580433864E-3,
        0.453342167309331,-0.507749535873652,-100.475154528389,-0.219201924648793,
        -3.21087965668917,607.567815637771,5.57686450685932E-4,0.187499040029550,
        9.05368030448107E-3,0.285417173048685,3.29924030996098E-2,0.239897419685483,
        4.82754995951394,-11.8035753702231,0.169490044091791,-1.79967222507787E-2,
        3.71810116332674E-2,-5.36288335065096E-2,1.60697101092520};
        double v__ = 0.0088; // m3/kg
        double p__ = 100; // MPa
        double h__ = 2800; // kJ/kg
        double pi = p/p__;
        double eta = h/h__;
        double omega = 0;

        for (int k=0; k<30; k++) {
            omega += n_[k] * Math.pow(pi+0.0661, i_[k]) * Math.pow(eta-0.720, j_[k]);
        }

        return omega * v__;
    }

    public static double t_ph(double p, double h) {
        if (h > h3ab(p)) return t_ph3b(p, h);
        else return t_ph3a(p, h);
    }

    static double t_ph3a(double p, double h) {
        int j_[] = {0,1,2,6,14,16,20,22,1,5,12,0,2,4,10,2,0,1,3,4,0,2,0,1,1,0,1,
        0,3,4,5};
        int i_[] = {-12,-12,-12,-12,-12,-12,-12,-12,-10,-10,-10,-8,-8,-8,-8,-5,
        -3,-2,-2,-2,-1,-1,0,0,1,3,3,4,4,10,12};
        double n_[] = {-1.33645667811215E-7,4.55912656802978E-6,-1.46294640700979E-5,
        6.39341312970080E-3,372.783927268847,-7186.54377460447,5.73494752103400E5,
        -2.67569329111439E6,-3.34066283302614E-5,-2.45479214069597E-2,47.8087847764996,
        7.64664131818904E-6,1.28350627676972E-3,1.71219081377331E-2,-8.51007304583213,
        -1.36513461629781E-2,-3.84460997596657E-6,3.37423807911655E-3,-0.551624873066791,
        0.729202277107470,-9.92522757376041E-3,-0.119308831407288,0.793929190615421,
        0.454270731799386,0.209998591259910,-6.42109823904738E-3,-2.35155868604540E-2,
        2.52233108341612E-3,-7.64885133368119E-3,1.36176427574291E-2,-1.33027883575669E-2};
        double p__ = 100; // MPa
        double h__ = 2300; // kJ/kg
        double t__ = 760; // K
        double pi = p/p__;
        double eta = h/h__;
        double theta = 0;

        for (int k=0; k<31; k++) {
            theta += n_[k] * Math.pow(pi+0.240, i_[k]) * Math.pow(eta-0.615, j_[k]);
        }

        return theta * t__;
    }

    static double t_ph3b(double p, double h) {
        int i_[] = {-12,-12,-10,-10,-10,-10,-10,-8,-8,-8,-8,-8,-6,-6,-6,-4,-4,-3,
        -2,-2,-1,-1,-1,-1,-1,-1,0,0,1,3,5,6,8};
        int j_[] = {0,1,0,1,5,10,12,0,1,2,4,10,0,1,2,0,1,5,0,4,2,4,6,10,14,16,0,
        2,1,1,1,1,1};
        double n_[] = {3.23254573644920E-5,-1.27575556587181E-4,-4.75851877356068E-4,
        1.56183014181602E-3,0.105724860113781,-85.8514221132534,724.140095480911,
        2.96475810273257E-3,-5.92721983365988E-3,-1.26305422818666E-2,-0.115716196364853,
        84.9000969739595,-1.08602260086615E-2,1.54304475328851E-2,7.50455441524466E-2,
        2.52520973612982E-2,-6.02507901232996E-2,-3.07622221350501,-5.74011959864879E-2,
        5.03471360939849,-0.925081888584834,3.91733882917546,-77.3146007130190,
        9493.08762098587,-1.41043719679409E6,8.49166230819026E6,0.861095729446704,
        0.323346442811720,0.873281936020439,-0.436653048526683,0.286596714529479,
        -0.131778331276228,6.76682064330275E-3};
        double p__ = 100; // MPa
        double h__ = 2800; // kJ/kg
        double t__ = 860; // K
        double pi = p/p__;
        double eta = h/h__;
        double theta = 0;

        for (int k=0; k<33; k++) {
            theta += n_[k] * Math.pow(pi+0.298, i_[k]) * Math.pow(eta-0.720, j_[k]);
        }

        return theta * t__;
    }

    public static double v_ps(double p, double s) {
        if (s < 4.41202148223476) return v_ps3a(p, s);
        else return v_ps3b(p, s);
    }

    static double v_ps3a(double p, double s) {
        int i_[] = {-12,-12,-12,-10,-10,-10,-10,-8,-8,-8,-8,-6,-5,-4,-3,-3,-2,-2,
        -1,-1,0,0,0,1,2,4,5,6};
        int j_[] = {10,12,14,4,8,10,20,5,6,14,16,28,1,5,2,4,3,8,1,2,0,1,3,0,0,2,
        2,0};
        double n_[] = {79.5544074093975,-2382.61242984590,1.76813100617787E4,
        -1.10524727080379E-3,-15.3213833655326,297.544599376982,-3.50315206871242E7,
        0.277513761062119,-0.523964271036888,-1.48011182995403E5,1.60014899374266E6,
        1.70802322663427E12,2.46866996006494E-4,1.65326084797980,-0.118008384666987,
        2.53798642355900,0.965127704669424,-28.2172420532826,0.203224612353823,
        1.10648186063513,0.526127948451280,0.277000018736321,1.08153340501132,
        -7.44127885357893E-2,1.64094443541384E-2,-6.80468275301065E-2,
        2.57988576101640E-2,-1.45749861944416E-4};
        double p__ = 100; // MPa
        double v__ = 0.0028; // m3/kg
        double s__ = 4.4; // kJ/(kg K)
        double pi = p/p__;
        double sigma = s/s__;
        double omega = 0;

        for (int k=0; k<28; k++) {
            omega += n_[k] * Math.pow(pi+0.187, i_[k]) * Math.pow(sigma-0.755, j_[k]);
        }

        return omega * v__;
    }

    static double v_ps3b(double p, double s) {
        int i_[] = {-12,-12,-12,-12,-12,-12,-10,-10,-10,-10,-8,-5,-5,-5,-4,-4,-4,
        -4,-3,-2,-2,-2,-2,-2,-2,0,0,0,1,1,2};
        int j_[] = {0,1,2,3,5,6,0,1,2,4,0,1,2,3,0,1,2,3,1,0,1,2,3,4,12,0,1,2,0,2,2};
        double n_[] = {5.91599780322238E-5,-1.85465997137856E-3,1.04190510480013E-2,
        5.98647302038590E-3,-0.771391189901699,1.72549765557036,-4.67076079846526E-4,
        1.34533823384439E-2,-8.08094336805495E-2,0.508139374365767,1.28584643361683E-3,
        -1.63899353915435,5.86938199318063,-2.92466667918613,-6.14076301499537E-3,
        5.76199014049172,-12.1613320606788,1.67637540957944,-7.44135838773463,
        3.78168091437659E-2,4.01432203027688,16.0279837479185,3.17848779347728,
        -3.58362310304853,-1.15995260446827E6,0.199256573577909,-0.122270624794624,
        -19.1449143716586,-1.50448002905284E-2,14.6407900162154,-3.27477787188230};
        double p__ = 100; // MPa
        double v__ = 0.0088; // m3/kg
        double s__ = 5.3; // kJ/(kg K)
        double pi = p/p__;
        double sigma = s/s__;
        double omega = 0;

        for (int k=0; k<31; k++) {
            omega += n_[k] * Math.pow(pi+0.298, i_[k]) * Math.pow(sigma-0.816, j_[k]);
        }

        return omega * v__;
    }

    public static double t_ps(double p, double s) {
        if (s < 4.41202148223476) return t_ps3a(p, s);
        else return t_ps3b(p, s);
    }

    static double t_ps3a(double p, double s) {
        int i_[] = {-12,-12,-10,-10,-10,-10,-8,-8,-8,-8,-6,-6,-6,-5,-5,-5,-4,-4,
        -4,-2,-2,-1,-1,0,0,0,1,2,2,3,8,8,10};
        int j_[] = {28,32,4,10,12,14,5,7,8,28,2,6,32,0,14,32,6,10,36,1,4,1,6,0,1,
        4,0,0,3,2,0,1,2};
        double n_[] = {1.50042008263875E9,-1.59397258480424E11,5.02181140217975E-4,
        -67.2057767855466,1450.58545404456,-8238.89534888890,-0.154852214233853,
        11.2305046746695,-29.7000213482822,4.38565132635495E10,1.37837838635464E-3,
        -2.97478527157462,9.71777947349413E12,-5.71527767052398E-5,2.88307949778420E4,
        -7.44428289262703E13,12.8017324848921,-368.275545889071,6.64768904779177E15,
        4.49359251958880E-2,-4.22897836099655,-0.240614376434179,-4.74341365254924,
        0.724093999126110,0.923874349695897,3.99043655281015,3.84066651868009E-2,
        -3.59344365571848E-3,-0.735196448821653,0.188367048396131,1.41064266818704E-4,
        -2.57418501496337E-3,1.23220024851555E-3};
        double p__ = 100; //MPa
        double t__ = 760; //K
        double s__ = 4.4; //kJ/(kg K)
        double pi = p/p__;
        double sigma = s/s__;
        double theta = 0;

        for (int k=0; k<33; k++) {
            theta += n_[k] * Math.pow(pi+0.240, i_[k]) * Math.pow(sigma-0.703, j_[k]);
        }

        return theta * t__;
    }

    static double t_ps3b(double p, double s) {
        int i_[] = {-12,-12,-12,-12,-8,-8,-8,-6,-6,-6,-5,-5,-5,-5,-5,-4,-3,-3,-2,
        0,2,3,4,5,6,8,12,14};
        int j_[] = {1,3,4,7,0,1,3,0,2,4,0,1,2,4,6,12,1,6,2,0,1,1,0,24,0,3,1,2};
        double n_[] = {0.527111701601660,-40.1317830052742,153.020073134484,
        -2247.99398218827,-0.193993484669048,-1.40467557893768,42.6799878114024,
        0.752810643416743,22.6657238616417,-622.873556909932,-0.660823667935396,
        0.841267087271658,-25.3717501764397,485.708963532948,880.531517490555,
        2.65015592794626E6,-0.359287150025783,-656.991567673753,2.41768149185367,
        0.856873461222588,0.655143675313458,-0.213535213206406,5.62974957606348E-3,
        -3.16955725450471E14,-6.99997000152457E-4,1.19845803210767E-2,
        1.93848122022095E-5,-2.15095749182309E-5};
        double p__ = 100; //MPa
        double t__ = 860; //K
        double s__ = 5.3; //kJ/(kg K)
        double pi = p/p__;
        double sigma = s/s__;
        double theta = 0;

        for (int k=0; k<28; k++) {
            theta += n_[k] * Math.pow(pi+0.760, i_[k]) * Math.pow(sigma-0.818, j_[k]);
        }

        return theta * t__;
    }

    public static double psat_h(double h) {
        final double H1 = 1.670858218E3;
        final double H2 = 2.563592004E3;
        if (h < H1 || h > H2) return Double.NaN;

        int i_[] = {0,1,1,1,1,5,7,8,14,20,22,24,28,36};
        int j_[] = {0,1,3,4,36,3,0,24,16,16,3,18,8,24};
        double n_[] = {0.600073641753024,-9.36203654849857,24.6590798594147,
        -107.014222858224,-9.15821315805768E13,-8623.32011700662,-23.5837344740032,
        2.52304969384128E17,-3.89718771997719E18,-3.33775713645296E22,3.56499469636328E10,
        -1.48547544720641E26,3.30611514838798E18,8.13641294467829E37};
        double p__ = 22; // MPa
        double h__ = 2600; // kJ/kg
        double eta = h/h__;
        double pi = 0;

        for (int k=0; k<14; k++) {
            pi += n_[k] * Math.pow(eta-1.02, i_[k]) * Math.pow(eta-0.608, j_[k]);
        }

        return pi * p__;
    }

    public static double psat_s(double s) {
        final double S1 = 3.778281340;
        final double S2 = 5.210887825;
        if (s < S1 || s > S2) return Double.NaN;

        int i_[] = {0,1,1,4,12,12,16,24,28,32};
        int j_[] = {0,1,32,7,4,14,36,10,0,18};
        double n_[] = {0.639767553612785,-12.9727445396014,-2.24595125848403E15,
        1.77466741801846E6,7.17079349571538E9,-3.78829107169011E17,-9.55586736431328E34,
        1.87269814676188E23,1.19254746466473E11,1.10649277244882E36};
        double p__ = 22; // MPa
        double s__ = 5.2; // kJ/(kg K)
        double sigma = s/s__;
        double pi = 0;

        for (int k=0; k<10; k++) {
            pi += n_[k] * Math.pow(sigma-1.03, i_[k]) * Math.pow(sigma-0.699, j_[k]);
        }

        return pi * p__;
    }

    public static double p_hs(double h, double s) {
        if (s < 4.41202148223476) return p_hs3a(h, s); // test for 2-phase region [done]
        else return p_hs3b(h, s);
    }

    static double p_hs3a(double h, double s) {
        int i_[] = {0,0,0,1,1,1,1,1,2,2,3,3,3,4,4,4,4,5,6,7,8,10,10,14,18,20,22,
        22,24,28,28,32,32};
        int j_[] = {0,1,5,0,3,4,8,14,6,16,0,2,3,0,1,4,5,28,28,24,1,32,36,22,28,
        36,16,28,36,16,36,10,28};
        double n_[] = {7.70889828326934,-26.0835009128688,267.416218930389,
        17.2221089496844,-293.542332145970,614.135601882478,-6.10562757725674E4,
        -6.51272251118219E7,7.35919313521937E4,-1.16646505914191E10,35.5267086434461,
        -596.144543825955,-475.842430145708,69.6781965359503,335.674250377312,
        2.50526809130882E4,1.46997380630766E5,5.38069315091534E19,1.43619827291346E21,
        3.64985866165994E19,-2547.41561156775,2.40120197096563E27,-3.93847464679496E29,
        1.47073407024852E24,-4.26391250432059E31,1.94509340621077E38,6.66212132114896E23,
        7.06777016552858E33,1.75563621975576E41,1.08408607429124E28,7.30872705175151E43,
        1.59145847398870E24,3.77121605943324E40};
        double p__ = 99; // MPa
        double h__ = 2300; // kJ/kg
        double s__ = 4.4; // kJ/(kg K)
        double eta = h/h__;
        double sigma = s/s__;
        double pi = 0;

        for (int k=0; k<33; k++) {
            pi += n_[k] * Math.pow(eta-1.01, i_[k]) * Math.pow(sigma-0.750, j_[k]);
        }

        return pi * p__;
    }

    static double p_hs3b(double h, double s) {
        int i_[] = {-12,-12,-12,-12,-12,-10,-10,-10,-10,-8,-8,-6,-6,-6,-6,-5,-4,
        -4,-4,-3,-3,-3,-3,-2,-2,-1,0,2,2,5,6,8,10,14,14};
        int j_[] = {2,10,12,14,20,2,10,14,18,2,8,2,6,7,8,10,4,5,8,1,3,5,6,0,1,0,3,
        0,1,0,1,1,1,3,7};
        double n_[] = {1.25244360717979E-13,-1.26599322553713E-2,5.06878030140626,
        31.7847171154202,-3.91041161399932E5,-9.75733406392044E-11,-18.6312419488279,
        510.973543414101,3.73847005822362E5,2.99804024666572E-8,20.0544393820342,
        -4.98030487662829E-6,-10.2301806360030,55.2819126990325,-206.211367510878,
        -7940.12232324823,7.82248472028153,-58.6544326902468,3550.73647696481,
        -1.15303107290162E-4,-1.75092403171802,257.981687748160,-727.048374179467,
        1.21644822609198E-4,3.93137871762692E-2,7.04181005909296E-3,-82.9108200698110,
        -0.265178818131250,13.7531682453991,-52.2394090753046,2405.56298941048,
        -2.27361631268929E4,8.90746343932567E4,-2.39234565822486E7,5.68795808129714E9};
        double p__ = 16.6; // MPa
        double h__ = 2800; // kJ/kg
        double s__ = 5.3; // kJ/(kg K)
        double eta = h/h__;
        double sigma = s/s__;
        double pi = 0;

        for (int k=0; k<35; k++) {
            pi += n_[k] * Math.pow(eta-0.681, i_[k]) * Math.pow(sigma-0.792, j_[k]);
        }

        return p__/pi;
    }

    public static double t_hs(double h, double s) {
        return t_ph(p_hs(h, s), h);
    }

    public static double v_hs(double h, double s) {
        return v_ps(p_hs(h, s), s);
    }

    // --- Backward equations v(p, T) and associated functions
    /**
     * Backward equation v(p,T)
     * @param p pressure
     * @param t absolute temperature
     * @return specific volume
     */
    public static double v(double p, double t) {
        double[] v__ = {0.0024,0.0041,0.0022,0.0029,0.0032,0.0064,0.0027,0.0032,
        0.0041,0.0054,0.0077,0.0026,0.0028,0.0031,0.0034,0.0041,0.0022,0.0054,
        0.0022,0.0088,0.0026,0.0031,0.0039,0.0049,0.0031,0.0038};
        double[] p__ = {100,100,40,40,40,40,25,25,25,25,25,24,23,23,23,23,23,23,
        21,20,23,23,23,23,22,22};
        double[] t__ = {760,860,690,690,710,730,660,660,660,670,680,650,650,650,
        650,650,650,650,640,650,650,650,650,650,650,650};
        int[] N = {30,32,35,38,29,42,38,29,42,29,34,43,40,39,24,27,24,27,29,33,
        38,39,35,36,20,23};
        double[] a = {0.085,0.280,0.259,0.559,0.587,0.587,0.872,0.898,0.910,0.875,
        0.802,0.908,1.000,0.976,0.974,0.972,0.848,0.874,0.886,0.803,0.902,0.960,
        0.959,0.910,0.996,0.993};
        double[] b = {0.817,0.779,0.903,0.939,0.918,0.891,0.971,0.983,0.984,0.964,
        0.935,0.989,0.997,0.997,0.996,0.997,0.983,0.982,0.990,1.020,0.988,0.995,
        0.995,0.988,0.994,0.994};
        double[] c = {1,1,1,1,1,0.5,1,1,0.5,0.5,1,1,1,0,0.5,0.5,1,1,1,1,1,1,1,1,
        1,1};
        double[] d = {1,1,1,1,1,1,1,1,1,1,1,1,0.25,0,1,1,1,1,1,1,1,1,1,1,1,1};
        double[] e = {1,1,1,4,1,4,4,4,4,4,1,4,1,0,1,1,4,1,4,1,1,1,4,1,4,4};
        int[][] i_ = {{-12,-12,-12,-10,-10,-10,-8,-8,-8,-6,-5,-5,-5,-4,-3,-3,-3,
        -3,-2,-2,-2,-1,-1,-1,0,0,1,1,2,2},//3a
            {-12,-12,-10,-10,-8,-6,-6,-6,-5,-5,-5,-4,-4,-4,-3,-3,-3,-3,-3,-2,-2,
        -2,-1,-1,0,0,1,1,2,3,4,4},//3b
            {-12,-12,-12,-10,-10,-10,-8,-8,-8,-6,-5,-5,-5,-4,-4,-3,-3,-2,-2,-2,-1,
        -1,-1,0,0,0,1,1,2,2,2,2,3,3,8},//3c
            {-12,-12,-12,-12,-12,-12,-10,-10,-10,-10,-10,-10,-10,-8,-8,-8,-8,-6,
        -6,-5,-5,-5,-5,-4,-4,-4,-3,-3,-2,-2,-1,-1,-1,0,0,1,1,3},//3d
            {-12,-12,-10,-10,-10,-10,-10,-8,-8,-8,-6,-5,-4,-4,-3,-3,-3,-2,-2,-2,
        -2,-1,0,0,1,1,1,2,2},//3e
            {0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,4,5,5,6,7,7,10,12,12,12,14,14,14,14,
        14,16,16,18,18,20,20,20,22,24,24,28,32},//3f
            {-12,-12,-12,-12,-12,-12,-10,-10,-10,-8,-8,-8,-8,-6,-6,-5,-5,-4,-3,
        -2,-2,-2,-2,-1,-1,-1,0,0,0,1,1,1,3,5,6,8,10,10},//3g
            {-12,-12,-10,-10,-10,-10,-10,-10,-8,-8,-8,-8,-8,-6,-6,-6,-5,-5,-5,
        -4,-4,-3,-3,-2,-1,-1,0,1,1},//3h
            {0,0,0,1,1,1,1,2,3,3,4,4,4,5,5,5,7,7,8,8,10,12,12,12,14,14,14,14,18,
        18,18,18,18,20,20,22,24,24,32,32,36,36},//3i
            {0,0,0,1,1,1,2,2,3,4,4,5,5,5,6,10,12,12,14,14,14,16,18,20,20,24,24,
        28,28},//3j
            {-2,-2,-1,-1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,5,5,5,6,6,6,6,
        8,10,12},//3k
            {-12,-12,-12,-12,-12,-10,-10,-8,-8,-8,-8,-8,-8,-8,-6,-5,-5,-4,-4,-3,
        -3,-3,-3,-2,-2,-2,-1,-1,-1,0,0,0,0,1,1,2,4,5,5,6,10,10,14},//3l
            {0,3,8,20,1,3,4,5,1,6,2,4,14,2,5,3,0,1,1,1,28,2,16,0,5,0,3,4,12,16,
        1,8,14,0,2,3,4,8,14,24},//3m
            {0,3,4,6,7,10,12,14,18,0,3,5,6,8,12,0,3,7,12,2,3,4,2,4,7,4,3,5,6,0,
        0,3,1,0,1,0,1,0,1},//3n
            {0,0,0,2,3,4,4,4,4,4,5,5,6,7,8,8,8,10,10,14,14,20,20,24},//3o
            {0,0,0,0,1,2,3,3,4,6,7,7,8,10,12,12,12,14,14,14,16,18,20,22,24,24,36},//3p
            {-12,-12,-10,-10,-10,-10,-8,-6,-5,-5,-4,-4,-3,-2,-2,-2,-2,-1,-1,-1,
            0,1,1,1},//3q
            {-8,-8,-3,-3,-3,-3,-3,0,0,0,0,3,3,8,8,8,8,10,10,10,10,10,10,10,10,12,
            14},//3r
            {-12,-12,-10,-8,-6,-5,-5,-4,-4,-3,-3,-2,-1,-1,-1,0,0,0,0,1,1,3,3,3,
            4,4,4,5,14},//3s
            {0,0,0,0,1,1,2,2,2,3,3,4,4,7,7,7,7,7,10,10,10,10,10,18,20,22,22,24,
            28,32,32,32,36},//3t
            {-12,-10,-10,-10,-8,-8,-8,-6,-6,-5,-5,-5,-3,-1,-1,-1,-1,0,0,1,2,2,3,
            5,5,5,6,6,8,8,10,12,12,12,14,14,14,14},//3u
            {-10,-8,-6,-6,-6,-6,-6,-6,-5,-5,-5,-5,-5,-5,-4,-4,-4,-4,-3,-3,-3,-2,
            -2,-1,-1,0,0,0,1,1,3,4,4,4,5,8,10,12,14},//3v
            {-12,-12,-10,-10,-8,-8,-8,-6,-6,-6,-6,-5,-4,-4,-3,-3,-2,-2,-1,-1,-1,
            0,0,1,2,2,3,3,5,5,5,8,8,10,10},//3w
            {-8,-6,-5,-4,-4,-4,-3,-3,-1,0,0,0,1,1,2,3,3,3,4,5,5,5,6,8,8,8,8,10,
            12,12,12,12,14,14,14,14},//3x
            {0,0,0,0,1,2,2,2,2,3,3,3,4,4,5,5,8,8,10,12},//3y
            {-8,-6,-5,-5,-4,-4,-4,-3,-3,-3,-2,-1,0,1,2,3,3,6,6,6,6,8,8}/*3z*/};
        int[][] j_ = {{5,10,12,5,10,12,5,8,10,1,1,5,10,8,0,1,3,6,0,2,3,0,1,2,0,1,
        0,2,0,2},//3a
            {10,12,8,14,8,5,6,8,5,8,10,2,4,5,0,1,2,3,5,0,2,5,0,2,0,1,0,2,0,2,0,1},//3b
            {6,8,10,6,8,10,5,6,7,8,1,4,7,2,8,0,3,0,4,5,0,1,2,0,1,2,0,2,0,1,3,7,0,
            7,1},//3c
            {4,6,7,10,12,16,0,2,4,6,8,10,14,3,7,8,10,6,8,1,2,5,7,0,1,7,2,4,0,1,0,
            1,5,0,2,0,6,0},//3d
            {14,16,3,6,10,14,16,7,8,10,6,6,2,4,2,6,7,0,1,3,4,0,0,1,0,4,6,0,2},//3e
            {-3,-2,-1,0,1,2,-1,1,2,3,0,1,-5,-2,0,-3,-8,1,-6,-4,1,-6,-10,-8,-4,-12,
            -10,-8,-6,-4,-10,-8,-12,-10,-12,-10,-6,-12,-12,-4,-12,-12},//3f
            {7,12,14,18,22,24,14,20,24,7,8,10,12,8,22,7,20,22,7,3,5,14,24,2,8,18,
            0,1,2,0,1,3,24,22,12,3,0,6},//3g
            {8,12,4,6,8,10,14,16,0,1,6,7,8,4,6,8,2,3,4,2,4,1,2,0,0,2,0,0,2},//3h
            {0,1,10,-4,-2,-1,0,0,-5,0,-3,-2,-1,-6,-1,12,-4,-3,-6,10,-8,-12,-6,-4,
            -10,-8,-4,5,-12,-10,-8,-6,2,-12,-10,-12,-12,-8,-10,-5,-10,-8},//3i
            {-1,0,1,-2,-1,1,-1,1,-2,-2,2,-3,-2,0,3,-6,-8,-3,-10,-8,-5,-10,-12,
            -12,-10,-12,-6,-12,-5},//3j
            {10,12,-5,6,-12,-6,-2,-1,0,1,2,3,14,-3,-2,0,1,2,-8,-6,-3,-2,0,4,-12,
            -6,-3,-12,-10,-8,-5,-12,-12,-10},//3k
            {14,16,18,20,22,14,24,6,10,12,14,18,24,36,8,4,5,7,16,1,3,18,20,2,3,
            10,0,1,3,0,1,2,12,0,16,1,0,0,1,14,4,12,10},//3l
            {0,0,0,2,5,5,5,5,6,6,7,8,8,10,10,12,14,14,18,20,20,22,22,24,24,28,28,
            28,28,28,32,32,32,36,36,36,36,36,36,36},//3m
            {-12,-12,-12,-12,-12,-12,-12,-12,-12,-10,-10,-10,-10,-10,-10,-8,-8,
            -8,-8,-6,-6,-6,-5,-5,-5,-4,-3,-3,-3,-2,-1,-1,0,1,1,2,4,5,6},//3n
            {-12,-4,-1,-1,-10,-12,-8,-5,-4,-1,-4,-3,-8,-12,-10,-8,-4,-12,-8,-12,
            -8,-12,-10,-12},//3o
            {-1,0,1,2,1,-1,-3,0,-2,-2,-5,-4,-2,-3,-12,-6,-5,-10,-8,-3,-8,-8,-10,
            -10,-12,-8,-12},//3p
            {10,12,6,7,8,10,8,6,2,5,3,4,3,0,1,2,4,0,1,2,0,0,1,3},//3q
            {6,14,-3,3,4,5,8,-1,0,1,5,-6,-2,-12,-10,-8,-5,-12,-10,-8,-6,-5,-4,-3,
            -2,-12,-12},//3r
            {20,24,22,14,36,8,16,6,32,3,8,4,1,2,3,0,1,4,28,0,32,0,1,2,3,18,24,4,24},//3s
            {0,1,4,12,0,10,0,6,14,3,8,0,10,3,4,7,20,36,10,12,14,16,22,18,32,22,
            36,24,28,22,32,36,36},//3t
            {14,10,12,14,10,12,14,8,12,4,8,12,2,-1,1,12,14,-3,1,-2,5,10,-5,-4,2,
            3,-5,2,-8,8,-4,-12,-4,4,-12,-10,-6,6},//3u
            {-8,-12,-12,-3,5,6,8,10,1,2,6,8,10,14,-12,-10,-6,10,-3,10,12,2,4,-2,
            0,-2,6,10,-12,-10,3,-6,3,10,2,-12,-2,-3,1},//3v
            {8,14,-1,8,6,8,14,-4,-3,2,8,-10,-1,3,-10,3,1,2,-8,-4,1,-12,1,-1,-1,
            2,-12,-5,-10,-8,-6,-12,-10,-12,-8},//3w
            {14,10,10,1,2,14,-2,12,5,0,4,10,-10,-1,6,-12,0,8,3,-6,-2,1,1,-6,-3,
            1,8,-8,-10,-8,-5,-4,-12,-10,-8,-6},//3x
            {-3,1,5,8,8,-4,-1,4,5,-8,4,8,-6,6,-2,1,-8,-2,-5,-8},//3y
            {3,6,6,8,5,6,8,-2,5,6,2,-6,3,1,6,-6,-2,-6,-5,-4,-1,-8,-4}/*3z*/};
        double[][] n_ = {{1.10879558823853E-3,572.616740810616,-7.67051948380852E4,
        -2.53321069529674E-2,6280.08049345689,2.34105654131876E5,0.216867826045856,
        -156.237904341963,-2.69893956176613E4,-1.80407100085505E-4,1.16732227668261E-3,
        26.6987040856040,2.82776617243286E4,-2424.31520029523,4.35217323022733E-4,
        -1.22494831387441E-2,1.79357604019989,44.2729521058314,-5.93223489018342E-3,
        0.453186261685774,1.35825703129140,4.08748415856745E-2,0.474686397863312,
        1.18646814997915,0.546987265727549,0.195266770452643,-5.02268790869663E-2,
        -0.369645308193377,6.33828037528420E-3,7.97441793901017E-2},//3a
            {-8.27670470003621E-2,41.6887126010565,4.83651982197059E-2,
        -2.91032084950276E4,-111.422582236948,-2.02300083904014E-2,294.002509338515,
        140.244997609658,-344.384158811459,361.182452612149,-1406.99677420738,
        -2.02023902676481E-3,171.346792457471,-4.25597804058632,6.91346085000334E-6,
        1.51140509678925E-3,-4.16375290166236E-2,-41.3754957011042,-50.6673295721637,
        -5.72212965569023E-4,6.08817368401785,23.9600660256161,1.22261479925384E-2,
        2.16356057692938,0.398198903368642,-0.116892827834085,-0.102845919373532,
        -0.492676637589284,6.55540456406790E-2,-0.240462535078530,-2.69798180310075E-2,
        0.128369435967012},//3b
            {3.11967788763030,2.76713458847564E4,3.22583103403269E7,
        -342.416065095363,-8.99732529907377E5,-7.93892049821251E7,95.3193003217388,
        2297.84742345072,1.75336675322499E5,7.91214365222792E6,3.19933345844209E-5,
        -65.9508863555767,-8.33426563212851E5,6.45734680583292E-2,-3.82031020570813E6,
        4.06398848470079E-5,31.0327498492008,-8.92996718483724E-4,234.604891591616,
        3775.15668966951,1.58646812591361E-2,0.707906336241843,12.6016225146570,
        0.736143655772152,0.676544268999101,-17.8100588189137,-0.156531975531713,
        11.7707430048158,8.40143653860447E-2,-0.186442467471949,-44.0170203949645,
        1.23290423502494E6,-2.40650039730845E-2,-1.07077716660869E6,4.38319858566475E-2},//3c
            {-4.52484847171645E-10,3.15210389538801E-5,-2.14991352047545E-3,
        508.058874808345,-1.27123036845932E7,1.15371133120497E12,-1.97805728776273E-16,
        2.41554806033972E-11,-1.56481703640525E-6,2.77211346836625E-3,-20.3578994462286,
        1.44369489909053E6,-4.11254217946539E10,6.23449786243773E-6,-22.1774281146038,
        -6.89315087933158E4,-1.95419525060713E7,3163.73510564015,2.24040754426988E6,
        -4.36701347922356E-6,-4.04213852833996E-4,-348.153203414663,-3.85294213555289E5,
        1.35203700099403E-7,1.34648383271089E-4,1.25031835351736E5,9.68123678455841E-2,
        225.660517512438,-1.90102435341872E-4,-2.99628410819229E-2,5.00833915372121E-3,
        0.387842482998411,-1385.35367777182,0.870745245971773,1.71946252068742,
        -3.26650121426383E-2,4980.44171727877,5.51478022765087E-3},//3d
            {7.15815808404721E8,-1.14328360753449E11,3.76531002015720E-12,
        -9.03983668691157E-5,6.65695908836252E5,5.35364174960127E9,7.94977402335603E10,
        92.2230563421437,-1.42586073991215E5,-1.11796381424162E6,8961.21629640760,
        -6699.89239070491,4.51242538486834E-3,-33.9731325977713,-1.20523111552278,
        4.75992667717124E4,-2.66627750390341E5,-1.53314954386524E-4,0.305638404828265,
        123.654999499486,-1043.90794213011,-1.57496516174308E-2,0.685331118940253,
        1.78373462873903,-0.544674124878910,2045.29931318843,-2.28342359328752E4,
        0.413197481515899,-34.1931835910405},//3e
            {-2.51756547792325E-8,6.01307193668763E-6,-1.00615977450049E-3,
        0.999969140252192,2.14107759236486,-16.5175571959086,-1.41987303638727E-3,
        2.69251915156554,34.9741815858722,-30.0208695771783,-1.31546288252539,
        -8.39091277286169,1.81545608337015E-10,-5.91099206478909E-4,1.52115067087106,
        2.52956470663225E-5,1.00726265203786E-15,-1.49774533860650,-7.93940970562969E-10,
        -1.50290891264717E-4,1.51205531275133,4.70942606221652E-6,1.95049710391712E-13,
        -9.11627886266077E-9,6.04374640201265E-4,-2.25132933900136E-16,6.10916973582981E-12,
        -3.03063908043404E-7,-1.37796070798409E-5,-9.19296736666106E-4,6.39288223132545E-10,
        7.53259479898699E-7,-4.00321478682929E-13,7.56140294351614E-9,-9.12082054034891E-12,
        -2.37612381140539E-8,2.69586010591874E-5,-7.32828135157839E-11,2.41995578306660E-10,
        -4.05735532730322E-4,1.89424143498011E-10,-4.86632965074563E-10},//3f
            {4.12209020652996E-5,-1.14987238280587E6,9.48180885032080E9,
        -1.95788865718971E17,4.96250704871300E24,-1.05549884548496E28,-7.58642165988278E11,
        -9.22172769596101E22,7.25379072059348E29,-61.7718249205859,1.07555033344858E4,
        -3.79545802336487E7,2.28646846221831E11,-4.99741093010619E6,-2.80214310054101E30,
        1.04915406769586E6,6.13754229168619E27,8.02056715528378E31,-2.98617819828065E7,
        -91.0782540134681,1.35033227281565E5,-7.12949383408211E18,-1.04578785289542E36,
        30.4331584444093,5.93250797959445E9,-3.64174062110798E27,0.921791403532461,
        -0.337693609657471,-72.4644143758508,-0.110480239272601,5.36516031875059,
        -2914.41872156205,6.16338176535305E39,-1.20889175861180E38,8.18396024524612E22,
        9.40781944835829E8,-3.67279669545448E4,-8.37513931798655E15},//3g
            {5.61379678887577E-2,7.74135421587083E9,1.11482975877938E-9,
        -1.43987128208183E-3,1936.96558764920,-6.05971823585005E8,1.71951568124337E13,
        -1.85461154985145E16,3.87851168078010E-17,-3.95464327846105E-14,-170.875935679023,
        -2120.10620701220,1.77683337348191E7,11.0177443629575,-2.34396091693313E5,
        -6.56174421999594E6,1.56362212977396E-5,-2.12946257021400,13.5249306374858,
        0.177189164145813,1394.99167345464,-7.03670932036388E-3,-0.152011044389648,
        9.81916922991113E-5,1.47199658618076E-3,20.2618487025578,0.899345518944240,
        -0.211346402240858,24.9971752957491},//3h
            {1.06905684359136,-1.48620857922333,2.59862256980408E14,
        -4.46352055678749E-12,-5.66620757170032E-7,-2.35302885736849E-3,-0.269226321968839,
        9.22024992944392,3.57633505503772E-12,-17.3942565562222,7.00681785556229E-6,
        -2.67050351075768E-4,-2.31779669675624,-7.53533046979752E-13,4.81337131452891,
        -2.23286270422356E21,-1.18746004987383E-5,6.46412934136496E-3,-4.10588536330937E-10,
        4.22739537057241E19,3.13698180473812E-13,1.64395334345040E-24,-3.39823323754373E-6,
        -1.35268639905021E-2,-7.23252514211625E-15,1.84386437538366E-9,-4.63959533752385E-2,
        -9.92263100376750E13,6.88169154439335E-17,-2.22620998452197E-11,-5.40843018624083E-8,
        3.45570606200257E-3,4.22275800304086E10,-1.26974478770487E-15,9.27237985153679E-10,
        6.12670812016489E-14,-7.22693924063497E-12,-3.83669502636822E-4,3.74684572410204E-4,
        -9.31976897511086E4,-2.47690616026922E-2,65.8110546759474},//3i
            {-1.11371317395540E-4,1.00342892423685,5.30615581928979,
        1.79058760078792E-6,-7.28541958464774E-4,-18.7576133371704,1.99060874071849E-3,
        24.3574755377290,-1.77040785499444E-4,-2.59680385227130E-3,-198.704578406823,
        7.38627790224287E-5,-2.36264692844138E-3,-1.61023121314333,6223.22971786473,
        -9.60754116701669E-9,-5.10572269720488E-11,7.67373781404211E-3,6.63855469485254E-15,
        -7.17590735526745E-10,1.46564542926508E-5,3.09029474277013E-12,-4.64216300971708E-16,
        -3.90499637961161E-14,-2.36716126781431E-10,4.54652854268717E-12,-4.22271787482497E-3,
        2.83911742354706E-11,2.70929002720228},//3j
            {-4.01215699576099E8,4.84501478318406E10,3.94721471363678E-15,
        3.72629967374147E4,-3.69794374168666E-30,-3.80436407012452E-15,4.75361629970233E-7,
        -8.79148916140706E-4,0.844317863844331,12.2433162656600,-104.529634830279,
        589.702771277429,-2.91026851164444E13,1.70343072841850E-6,-2.77617606975748E-4,
        -3.44709605486686,22.1333862447095,-194.646110037079,8.08354639772825E-16,
        -1.80845209145470E-11,-6.96664158132412E-6,-1.81057560300994E-3,2.55830298579027,
        3289.13873658481,-1.73270241249904E-19,-6.61876792558034E-7,-3.95688923421250E-3,
        6.04203299819132E-18,-4.00879935920517E-14,1.60751107464958E-9,3.83719409025556E-5,
        -6.49565446702457E-15,-1.49095328506000E-12,5.41449377329581E-9},//3k
            {2.60702058647537E9,-1.88277213604704E14,5.54923870289667E18,
        -7.58966946387758E22,4.13865186848908E26,-8.15038000738060E11,-3.81458260489955E32,
        -1.23239564600519E-2,2.26095631437174E7,-4.95017809506720E11,5.29482996422863E15,
        -4.44359478746295E22,5.21635864527315E34,-4.87095672740742E54,-7.14430209937547E5,
        0.127868634615495,-10.0752127917598,7.77451437960990E6,-1.08105480796471E24,
        -3.57578581169659E-6,-2.12857169423484,2.70706111085238E29,-6.95953622348829E32,
        0.110609027472280,72.1559163361354,-3.06367307532219E14,2.65839618885530E-5,
        2.53392392889754E-2,-214.443041836579,0.937846601489667,2.23184043101700,
        33.8401222509191,4.94237237179718E20,-0.198068404154428,-1.41415349881140E30,
        -99.3862421613651,125.070534142731,-996.473529004439,4.73137909872765E4,
        1.16662121219322E32,-3.15874976271533E15,-4.45703369196945E32,6.42794932373694E32},//3l
            {0.811384363481847,-5681.99310990094,-1.78657198172556E10,
        7.95537657613427E31,-8.14568209346872E4,-6.59774567602874E7,-1.52861148659302E10,
        -5.60165667510446E11,4.58384828593949E5,-3.85754000383848E13,4.53735800004273E7,
        9.39454935735563E11,2.66572856432938E27,-5.47578313899097E9,2.00725701112386E14,
        1.85007245563239E12,1.85135446828337E8,-1.70451090076385E11,1.57890366037614E14,
        -2.02530509748774E15,3.68193926183570E59,1.70215539458936E17,6.39234909918741E41,
        -8.21698160721956E14,-7.95260241872306E23,2.33415869478510E17,-6.00079934586803E22,
        5.94584382273384E24,1.89461279349492E39,-8.10093428842645E45,1.88813911076809E21,
        1.11052244098768E35,2.91133958602503E45,-3.29421923951460E21,-1.37570282536696E25,
        1.81508996303902E27,-3.46865122768353E29,-2.11961148774260E37,-1.28617899887675E48,
        4.79817895699239E64},//3m
            {2.80967799943151E-39,6.14869006573609E-31,5.82238667048942E-28,
        3.90628369238462E-23,8.21445758255119E-21,4.02137961842776E-15,6.51718171878301E-13,
        -2.11773355803058E-8,2.64953354380072E-3,-1.35031446451331E-32,-6.07246643970893E-24,
        -4.02352115234494E-19,-7.44938506925544E-17,1.89917206526237E-13,3.64975183508473E-6,
        1.77274872361946E-26,-3.34952758812999E-19,-4.21537726098389E-9,-3.91048167929649E-2,
        5.41276911564176E-14,7.05412100773699E-12,2.58585887897486E-9,-4.93111362030162E-11,
        -1.58649699894543E-6,-0.525037427886100,2.20019901729615E-3,-6.43064132636925E-3,
        62.9154149015048,135.147318617061,2.40560808321713E-7,-8.90763306701305E-4,
        -4402.09599407714,-302.807107747776,1591.58748314599,2.32534272709876E5,
        -7.92681207132600E5,-8.69871364662769E10,3.54542769185671E11,4.00849240129329E14},//3n
            {1.28746023979718E-35,-7.35234770382342E-12,2.89078692149150E-3,
        0.244482731907223,1.41733492030985E-24,-3.54533853059476E-29,-5.94539202901431E-18,
        -5.85188401782779E-9,2.01377325411803E-6,1.38647388209306,-1.73959365084772E-5,
        1.37680878349369E-3,8.14897605805513E-15,4.25596631351839E-26,-3.87449113787755E-18,
        1.39814747930240E-13,-1.71849638951521E-3,6.41890529513296E-22,1.18960578072018E-11,
        -1.55282762571611E-18,2.33907907347507E-8,-1.74093247766213E-13,3.77682649089149E-9,
        -5.16720236575302E-11},//3o
            {-9.82825342010366E-5,1.05145700850612,116.033094095084,
        3246.64750281543,-1235.92348610137,-5.61403450013495E-2,8.56677401640869E-8,
        236.313425393924,9.72503292350109E-3,-1.03001994531927,-1.49653706199162E-9,
        -2.15743778861592E-5,-8.34452198291445,0.586602660564988,3.43480022104968E-26,
        8.16256095947021E-6,2.94985697916798E-3,7.11730466276584E-17,4.00954763806941E-10,
        10.7766027032853,-4.09449599138182E-7,-7.29121307758902E-6,6.77107970938909E-9,
        6.02745973022975E-8,-3.82323011855257E-11,1.79946628317437E-3,-3.45042834640005E-4},//3p
            {-8.20433843259950E4,4.73271518461586E10,-8.05950021005413E-2,
        32.8600025435980,-3566.17029982490,-1.72985781433335E9,3.51769232729192E7,
        -7.75489259985144E5,7.10346691966018E-5,9.93499883820274E4,-0.642094171904570,
        -6128.42816820083,232.808472983776,-1.42808220416837E-5,-6.43596060678456E-3,
        -4.28577227475614,2256.89939161918,1.00355651721510E-3,0.333491455143516,
        1.09697576888873,0.961917379376452,-8.38165632204598E-2,2.47795908411492,
        -3191.14969006533},//3q
            {1.44165955660863E-3,-7.01438599628258E12,-8.30946716459219E-17,
        0.261975135368109,393.097214706245,-1.04334030654021E4,4.90112654154211E8,
        -1.47104222772069E-4,1.03602748043408,3.05308890065089,-3.99745276971264E6,
        5.69233719593750E-12,-4.64923504407778E-2,-5.35400396512906E-18,3.99988795693162E-13,
        -5.36479560201811E-7,1.59536722411202E-2,2.70303248860217E-15,2.44247453858506E-8,
        -9.83430636716454E-6,6.63513144224454E-2,-9.93456957845006,546.491323528491,
        -1.43365406393758E4,1.50764974125511E5,-3.37209709340105E-10,3.77501980025469E-9},//3r
            {-5.32466612140254E22,1.00415480000824E31,-1.91540001821367E29,
        1.05618377808847E16,2.02281884477061E58,8.84585472596134E7,1.66540181638363E22,
        -3.13563197669111E5,-1.85662327545324E53,-6.24942093918942E-2,-5.04160724132590E9,
        1.87514491833092E4,1.21399979993217E-3,1.88317043049455,-1670.73503962060,
        0.965961650599775,2.94885696802488,-6.53915627346115E4,6.04012200163444E49,
        -0.198339358557937,-1.75984090163501E57,3.56314881403987,-575.991255144384,
        4.56213415338071E4,-1.09174044987829E7,4.37796099975134E33,-6.16552611135792E45,
        1.93568768917797E9,9.50898170425042E53},//3s
            {1.55287249586268,6.64235115009031,-2893.66236727210,
        -3.85923202309848E12,-2.91002915783761,-8.29088246858083E11,1.76814899675218,
        -5.34686695713469E8,1.60464608687834E17,1.96435366560186E5,1.56637427541729E12,
        -1.78154560260006,-2.29746237623692E15,3.85659001648006E7,1.10554446790543E9,
        -6.77073830687349E13,-3.27910592086523E30,-3.41552040860644E50,-5.27251339709047E20,
        2.45375640937055E23,-1.68776617209269E26,3.58958955867578E28,-6.56475280339411E35,
        3.55286045512301E38,5.69021454413270E57,-7.00584546433113E47,-7.05772623326374E64,
        1.66861176200148E52,-3.00475129680486E60,-6.68481295196808E50,4.28432338620678E68,
        -4.44227367758304E71,-2.81396013562745E76},//3t
            {1.22088349258355E17,1.04216468608488E9,-8.82666931564652E15,
        2.59929510849499E19,2.22612779142211E14,-8.78473585050085E17,-3.14432577551552E21,
        -2.16934916996285E12,1.59079648196849E20,-339.567617303423,8.84387651337836E12,
        -8.43405926846418E20,11.4178193518022,-1.22708229235641E-4,-106.201671767107,
        9.03443213959313E24,-6.93996270370852E27,6.48916718965575E-9,7189.57567127851,
        1.05581745346187E-3,-6.51903203602581E14,-1.60116813274676E24,-5.10254294237837E-9,
        -0.152355388953402,6.77143292290144E11,2.76378438378930E14,1.16862983141686E-2,
        -3.01426947980171E13,1.69719813884840E-8,1.04674840020929E26,-1.08016904560140E4,
        -9.90623601934295E-13,5.36116483602738E6,2.26145963747881E21,-4.88731565776210E-10,
        1.51001548880670E-5,-2.27700464643920E4,-7.81754507698846E27},//3u
            {-4.15652812061591E-55,1.77441742924043E-61,-3.57078668203377E-55,
        3.59252213604114E-26,-25.9123736380269,5.94619766193460E4,-6.24184007103158E10,
        3.13080299915944E16,1.05006446192036E-9,-1.92824336984852E-6,6.54144373749937E5,
        5.13117462865044E12,-6.97595750347391E18,-1.03977184454767E28,1.19563135540666E-48,
        -4.36677034051655E-42,9.26990036530639E-30,5.87793105620748E20,2.80375725094731E-18,
        -1.92359972440634E22,7.42705723302738E26,-51.7429682450605,8.20612048645469E6,
        -1.88214882341448E-9,1.84587261114837E-2,-1.35830407782663E-6,-7.23681885626348E16,
        -2.23449194054124E26,-1.11526741826431E-35,2.76032601145151E-29,1.34856491567853E14,
        6.52440293345860E-10,5.10655119774360E16,-4.68138358908732E31,-7.60667491183279E15,
        -4.17247986986821E-19,3.12545677756104E13,-1.00375333864186E14,2.47761392329058E26},//3v
            {-5.86219133817016E-8,-8.94460355005526E10,5.31168037519774E-31,
        0.109892402329239,-5.75368389425212E-2,2.28276853990249E4,-1.58548609655002E18,
        3.29865748576503E-28,-6.34987981190669E-25,6.15762068640611E-9,-9.61109240985747E7,
        -4.06274286652625E-45,-4.71103725498077E-13,0.725937724828145,1.87768525763682E-39,
        -1033.08436323771,-6.62552816342168E-2,579.514041765710,2.37416732616644E-27,
        2.71700235739893E-15,-90.7886213483600,-1.71242509570207E-37,156.792067854621,
        0.923261357901470,-5.97865988422577,3.21988767636389E6,-3.99441390042203E-30,
        4.93429086046981E-8,8.12036983370565E-20,-2.07610284654137E-12,-3.40821291419719E-7,
        5.42000573372233E-18,-8.56711586510214E-13,2.66170454405981E-14,8.58133791857099E-6},//3w
            {3.77373741298151E18,-5.07100883722913E12,-1.03363225598860E15,
        1.84790814320773E-6,-9.24729378390945E-4,-4.25999562292738E23,-4.62307771873973E-13,
        1.07319065855767E21,6.48662492280682E10,2.44200600688281,-8.51535733484258E9,
        1.69894481433592E21,2.15780222509020E-27,-0.320850551367334,-3.82642448458610E16,
        -2.75386077674421E-29,-5.63199253391666E5,-3.26068646279314E20,3.97949001553184E13,
        1.00824008584757E-7,1.62234569738433E4,-4.32355225319745E10,-5.92874245598610E11,
        1.33061647281106,1.57338197797544E6,2.58189614270853E13,2.62413209706358E24,
        -9.20011937431142E-2,2.20213765905426E-3,-11.0433759109547,8.47004870612087E6,
        -5.92910695762536E8,-1.83027173269660E-5,0.181339603516302,-1192.28759669889,
        4.30867658061468E6},//3x
            {-5.25597995024633E-10,5834.41305228407,-1.34778968457925E16,
        1.18973500934212E25,-1.59096490904708E26,-3.15839902302021E-7,496.212197158239,
        3.27777227273171E18,-5.27114657850696E21,2.10017506281863E-17,7.05106224399834E20,
        -2.66713136106469E30,-1.45370512554562E-8,1.49333917053130E27,-1.49795620287641E7,
        -3.81881906271100E15,7.24660165585797E-5,-9.37808169550193E13,5.14411468376383E9,
        -8.28198594040141E4},//3y
            {2.44007892290650E-11,-4.63057430331242E6,7.28803274777712E9,
        3.27776302858856E15,-1.10598170118409E9,-3.23899915729957E12,9.23814007023245E15,
        8.42250080413712E-13,6.63221436245506E11,-1.67170186672139E14,2537.49358701391,
        -8.19731559610523E-21,3.28380587890663E11,-6.25004791171543E7,8.03197957462023E20,
        -2.04397011338353E-11,-3783.91047055938,9.72876545938620E-3,15.4355721681459,
        -3739.62862928643,-6.82859011374572E10,-2.48488015614543E-4,3.94536049497068E6}/*3z*/};
        char subregion = getSubRegion(p, t);
        if (subregion < 'a') return Double.NaN;
        int eqn = subregion - 'a';
        double omega = 0;
        double pi = p/p__[eqn];
        double theta = t/t__[eqn];

        if (subregion == 'n') {
            for (int k=0; k < N[eqn]; k++) {
                omega += n_[eqn][k] * Math.pow(pi - a[eqn], i_[eqn][k])
                        * Math.pow(theta - b[eqn], j_[eqn][k]);
            }

            return v__[eqn] * Math.exp(omega);
        }

        for (int k=0; k < N[eqn]; k++) {
            omega += n_[eqn][k] * Math.pow(pi-a[eqn], c[eqn] * i_[eqn][k])
                    * Math.pow(theta-b[eqn], d[eqn] * j_[eqn][k]);
        }

        return v__[eqn] * Math.pow(omega, e[eqn]);
    }

    static char getSubRegion(double p, double t) {
        final double p3cd = 19.00881189173929;
        if (p > 100) return '-'; // invalid pressure
        if (p > 40) {
            return (t <= t3border("ab", p) ? 'a' : 'b');
        }
        if (p > 25) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= t3border("ab", p)) return 'd';
            if (t <= t3border("ef", p)) return 'e';
            return 'f';
        }
        if (p > 23.5) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= t3border("gh", p)) return 'g';
            if (t <= t3border("ef", p)) return 'h';
            if (t <= t3border("ij", p)) return 'i';
            if (t <= t3border("jk", p)) return 'j';
            return 'k';
        }
        if (p > 23) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= t3border("gh", p)) return 'l';
            if (t <= t3border("ef", p)) return 'h';
            if (t <= t3border("ij", p)) return 'i';
            if (t <= t3border("jk", p)) return 'j';
            return 'k';
        }
        if (p > 22.5) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= t3border("gh", p)) return 'l';
            if (t <= t3border("mn", p)) return 'm';
            if (t <= t3border("ef", p)) return 'n';
            if (t <= t3border("op", p)) return 'o';
            if (t <= t3border("ij", p)) return 'p';
            if (t <= t3border("jk", p)) return 'j';
            return 'k';
        }
        if (p > SteamCalc.psat(643.15)) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= t3border("qu", p)) return 'q';
            if (t >= t3border("rx", p) && t <= t3border("jk", p)) return 'r';
            if (t >  t3border("jk", p)) return 'k';

            if (p > 22.11) {
                if (t <= t3border("uv", p)) return 'u';
                if (t <= t3border("ef", p)) return 'v';
                if (t <= t3border("wx", p)) return 'w';
                return 'x';
            }
            if (p > 22.064) {
                if (t <= t3border("uv", p)) return 'u';
                if (t <= t3border("ef", p)) return 'y';
                if (t <= t3border("wx", p)) return 'z';
                return 'x';
            }
            if (t <= SteamCalc.tsat(p)) {
                if (p > 21.93161551) {
                    return (t <= t3border("uv", p)) ? 'u' : 'y';
                }
                return 'u';
            }
            else {
                if (p > 21.90096265) {
                    return (t <= t3border("wx", p)) ? 'z' : 'x';
                }
                return 'x';
            }
        }
        if (p > 20.5) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= SteamCalc.tsat(p)) return 's';
            if (t <= t3border("jk", p)) return 'r';
            return 'k';
        }
        if (p > p3cd) {
            if (t <= t3border("cd", p)) return 'c';
            if (t <= SteamCalc.tsat(p)) return 's';
            return 't';
        }
        if (p > SteamCalc.psat(623.15)) {
            return ((t <= SteamCalc.tsat(p)) ? 'c' : 't');
        }

        return '+'; // invalid pressure
    }

    static double t3border(String eqn, double p) {
        java.util.Map<String, int[]> iMap = new java.util.HashMap<String, int[]>();
        java.util.Map<String,  double[]> nMap = new java.util.HashMap<String, double[]>();
        iMap.put("ab", new int[] {0,1,2,-1,-2});
        nMap.put("ab", new double[] {1547.93642129415,-187.661219490113,21.3144632222113,
        -1918.87498864292,918.419702359447});
        iMap.put("cd", new int[] {0,1,2,3});
        nMap.put("cd", new double[] {585.276966696349,2.78233532206915,
        -1.27283549295878E-2,1.59090746562729E-4});
        iMap.put("gh", new int[] {0,1,2,3,4});
        nMap.put("gh", new double[] {-2.49284240900418E4,4281.43584791546,
        -269.029173140130,7.51608051114157,-7.87105249910383E-2});
        iMap.put("ij", new int[] {0,1,2,3,4});
        nMap.put("ij", new double[] {584.814781649163,-0.616179320924617,
        0.260763050899562,-5.87071076864459E-3,5.15308185433082E-5});
        iMap.put("jk", new int[] {0,1,2,3,4});
        nMap.put("jk", new double[] {617.229772068439,-7.70600270141675,
        0.697072596851896,-1.57391839848015E-2,1.37897492684194E-4});
        iMap.put("mn", new int[] {0,1,2,3});
        nMap.put("mn", new double[] {535.339483742384,7.61978122720128,
        -0.158365725441648,1.92871054508108E-3});
        iMap.put("op", new int[] {0,1,2,-1,-2});
        nMap.put("op", new double[] {969.461372400213,-332.500170441278,
        64.2859598466067,773.845935768222,-1523.13732937084});
        iMap.put("qu", new int[] {0,1,2,3});
        nMap.put("qu", new double[] {565.603648239126,5.29062258221222,
        -0.102020639611016,1.22240301070145E-3});
        iMap.put("rx", new int[] {0,1,2,3});
        nMap.put("rx", new double[] {584.561202520006,-1.02961025163669,
        0.243293362700452,-2.94905044740799E-3});
        iMap.put("uv", new int[] {0,1,2,3});
        nMap.put("uv", new double[] {528.199646263062,8.90579602135307,
        -0.222814134903755,2.86791682263697E-3});
        iMap.put("wx", new int[] {0,1,2,-1,-2});
        nMap.put("wx", new double[] {7.28052609145380,97.3505869861952,
        14.7370491183191,329.196213998375,873.371668682417});
        double p__ = 1; // MPa
        double t__ = 1; // K
        double pi = p/p__;
        double theta = 0;
        int[] i_;
        double[] n_;

        if (eqn.equals("ef")) {
            return t__ * (3.727888004 * (pi-22.064) + 647.096);
        }

        i_ = iMap.get(eqn);
        n_ = nMap.get(eqn);

        if (eqn.equals("ab") || eqn.equals("op") || eqn.equals("wx")) {
            for (int k=0; k < i_.length; k++) {
                theta += n_[k] * Math.pow(Math.log(pi), i_[k]);
            }

            return t__ * theta;
        }
        
        if (i_ == null) return Double.NaN;

        for (int k=0; k < i_.length; k++) {
            theta += n_[k] * Math.pow(pi, i_[k]);
        }

        return t__ * theta;
    }
}
